home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / GraphicsWorkshop / Source / Converters / PCX_SCRATCH / ppmtopcx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-14  |  8.5 KB  |  381 lines

  1. /* ppmtopcx.c - read a portable pixmap and produce a PCX file
  2. **
  3. ** Copyright (C) 1990 by Michael Davidson.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include <stdio.h>
  14. #include "ppm.h"
  15. #include "ppmcmap.h"
  16.  
  17. #define MAXCOLORS    256
  18. #define    MAXPLANES    4
  19.  
  20. /*
  21.  * Pointer to function returning an int
  22.  */
  23. typedef void (* vfunptr) ARGS(( int, int, unsigned char*, int, int ));
  24.  
  25. static void PCXEncode ARGS(( FILE* fp, int GWidth, int GHeight, int Colors, int Red[], int Green[], int Blue[], vfunptr GetPlanes ));
  26. static void PutPlane ARGS(( FILE* fp, unsigned char* buf, int Size ));
  27. static void ReadPlanes ARGS(( int y, int width, unsigned char* buf, int planes, int bits ));
  28. static void Putword ARGS(( int w, FILE* fp ));
  29. static void Putbyte ARGS(( int b, FILE* fp ));
  30.  
  31. static pixel** pixels;
  32. static colorhash_table cht;
  33.  
  34. void
  35. main( argc, argv )
  36.     int argc;
  37.     char* argv[];
  38.     {
  39.     FILE* ifp;
  40.     int argn, rows, cols, colors, i;
  41.     pixval maxval;
  42.     pixel black_pixel;
  43.     colorhist_vector chv;
  44.     int Red[MAXCOLORS], Green[MAXCOLORS], Blue[MAXCOLORS];
  45.     char* usage = "[ppmfile]";
  46.  
  47.     ppm_init( &argc, argv );
  48.  
  49.     argn = 1;
  50.  
  51.     if ( argn < argc )
  52.     {
  53.     ifp = pm_openr( argv[argn] );
  54.     ++argn;
  55.     }
  56.     else
  57.     ifp = stdin;
  58.  
  59.     if ( argn != argc )
  60.     pm_usage( usage );
  61.  
  62.     pixels = ppm_readppm( ifp, &cols, &rows, &maxval );
  63.  
  64.     pm_close( ifp );
  65.  
  66.     /* Figure out the colormap. */
  67.     pm_message( "computing colormap..." );
  68.     chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
  69.     if ( chv == (colorhist_vector) 0 )
  70.     pm_error(
  71.         "too many colors - try doing a 'ppmquant %d'", MAXCOLORS );
  72.     pm_message( "%d colors found", colors );
  73.  
  74.     /* Force black to slot 0 if possible. */
  75.     PPM_ASSIGN(black_pixel, 0, 0, 0 );
  76.     ppm_addtocolorhist(chv, &colors, MAXCOLORS, &black_pixel, 0, 0 );
  77.  
  78.     /* Now turn the ppm colormap into the appropriate PCX colormap. */
  79.     if ( maxval > 255 )
  80.     pm_message(
  81.         "maxval is not 255 - automatically rescaling colors" );
  82.     for ( i = 0; i < colors; ++i )
  83.     {
  84.     if ( maxval == 255 )
  85.         {
  86.         Red[i] = PPM_GETR( chv[i].color );
  87.         Green[i] = PPM_GETG( chv[i].color );
  88.         Blue[i] = PPM_GETB( chv[i].color );
  89.         }
  90.     else
  91.         {
  92.         Red[i] = (int) PPM_GETR( chv[i].color ) * 255 / maxval;
  93.         Green[i] = (int) PPM_GETG( chv[i].color ) * 255 / maxval;
  94.         Blue[i] = (int) PPM_GETB( chv[i].color ) * 255 / maxval;
  95.         }
  96.     }
  97.  
  98.     /* And make a hash table for fast lookup. */
  99.     cht = ppm_colorhisttocolorhash( chv, colors );
  100.     ppm_freecolorhist( chv );
  101.  
  102.     /* All set, let's do it. */
  103.     PCXEncode( stdout, cols, rows, colors, Red, Green, Blue, ReadPlanes );
  104.  
  105.     exit( 0 );
  106.     }
  107.  
  108. /*****************************************************************************
  109.  *
  110.  * PCXENCODE.C    - PCX Image compression interface
  111.  *
  112.  * PCXEncode( FName, GHeight, GWidth, Colors, Red, Green, Blue, GetPlanes )
  113.  *
  114.  *****************************************************************************/
  115.  
  116. #define TRUE 1
  117. #define FALSE 0
  118.  
  119. /* public */
  120.  
  121. static void
  122. PCXEncode(fp, GWidth, GHeight, Colors, Red, Green, Blue, GetPlanes )
  123. FILE* fp;
  124. int GWidth, GHeight;
  125. int Colors;
  126. int Red[], Green[], Blue[];
  127. vfunptr GetPlanes;
  128. {
  129.     int        BytesPerLine;
  130.     int        Planes;
  131.     int        BitsPerPixel;
  132.     unsigned char    *buf;
  133.     int        i;
  134.     int        n;
  135.     int        y;
  136.  
  137.     /*
  138.      * select number of planes and number of bits
  139.      * per pixel according to number of colors
  140.      */
  141.     /*
  142.      * 16 colors or less are handled as 1 bit per pixel
  143.      * with 1, 2, 3 or 4 color planes.
  144.      * more than 16 colors are handled as 8 bits per pixel
  145.      * with 1 plane
  146.      */
  147.     if (Colors > 16)
  148.     {
  149.         BitsPerPixel    = 8;
  150.         Planes        = 1;
  151.     }
  152.     else
  153.     {
  154.         BitsPerPixel    = 1;
  155.         if (Colors > 8)
  156.             Planes = 4;
  157.         else if (Colors > 4)
  158.             Planes = 3;
  159.         else if (Colors > 2)
  160.             Planes = 2;
  161.         else
  162.             Planes = 1;
  163.     }
  164.  
  165.         /*
  166.          * Write the PCX header
  167.          */
  168.     Putbyte( 0x0a, fp);        /* .PCX magic number        */
  169.     Putbyte( 0x05, fp);        /* PC Paintbrush version    */
  170.     Putbyte( 0x01, fp);        /* .PCX run length encoding    */
  171.     Putbyte( BitsPerPixel, fp);    /* bits per pixel        */
  172.  
  173.         Putword( 0, fp );        /* x1    - image left        */
  174.         Putword( 0, fp );        /* y1    - image top        */
  175.     Putword( GWidth-1, fp );    /* x2    - image right        */
  176.     Putword( GHeight-1, fp );    /* y2    - image bottom        */
  177.  
  178.     Putword( GWidth, fp );        /* horizontal resolution    */
  179.     Putword( GHeight, fp );        /* vertical resolution        */
  180.  
  181.         /*
  182.          * Write out the Color Map for images with 16 colors or less
  183.          */
  184.     n = (Colors <= 16) ? Colors : 16;
  185.         for (i = 0; i < n; ++i)
  186.     {
  187.                 Putbyte( Red[i], fp );
  188.                 Putbyte( Green[i], fp );
  189.                 Putbyte( Blue[i], fp );
  190.         }
  191.         for (; i < 16; ++i)
  192.     {
  193.                 Putbyte( 255, fp );
  194.                 Putbyte( 255, fp );
  195.                 Putbyte( 255, fp );
  196.         }
  197.  
  198.     Putbyte( 0, fp);        /* reserved byte        */
  199.  
  200.     Putbyte( Planes, fp);        /* number of color planes    */
  201.  
  202.     BytesPerLine    = ((GWidth * BitsPerPixel) + 7) / 8;
  203.     Putword( BytesPerLine, fp );    /* number of bytes per scanline    */
  204.  
  205.     Putword( 1, fp);        /* pallette info        */
  206.  
  207.     for (i = 0; i < 58; ++i)    /* fill to end of header    */
  208.         Putbyte( 0, fp );
  209.  
  210.     buf    = (unsigned char *)malloc( MAXPLANES * BytesPerLine );
  211.  
  212.     for (y = 0; y < GHeight; ++y)
  213.     {
  214.         (*GetPlanes)(y, GWidth, buf, Planes, BitsPerPixel);
  215.  
  216.         for (i = 0; i < Planes; ++i)
  217.             PutPlane(fp, buf + (i * BytesPerLine), BytesPerLine);
  218.     }
  219.  
  220.     /*
  221.      * color map for > 16 colors is at end of file
  222.      */
  223.     if (Colors > 16)
  224.     {
  225.         Putbyte( 0x0c, fp);        /* magic for 256 colors */
  226.             for (i = 0; i < Colors; ++i)
  227.         {
  228.                     Putbyte( Red[i], fp );
  229.                     Putbyte( Green[i], fp );
  230.                     Putbyte( Blue[i], fp );
  231.             }
  232.             for (; i < MAXCOLORS; ++i)
  233.         {
  234.                     Putbyte( 255, fp );
  235.                     Putbyte( 255, fp );
  236.                     Putbyte( 255, fp );
  237.             }
  238.     }
  239.  
  240.         fclose( fp );
  241. }
  242.  
  243. static void
  244. PutPlane(fp, buf, Size)
  245. FILE        *fp;
  246. unsigned char    *buf;
  247. int        Size;
  248. {
  249.     unsigned char    *end;
  250.     int        c;
  251.     int        previous;
  252.     int        count;
  253.  
  254.     end    = buf + Size;
  255.  
  256.     previous = *buf++;
  257.     count     = 1;
  258.  
  259.     while (buf < end)
  260.     {
  261.         c = *buf++;
  262.         if (c == previous && count < 63)
  263.         {
  264.             ++count;
  265.             continue;
  266.         }
  267.  
  268.         if (count > 1 || (previous & 0xc0) == 0xc0)
  269.         {
  270.             count |= 0xc0;
  271.             Putbyte ( count , fp );
  272.         }
  273.         Putbyte(previous, fp);
  274.         previous = c;
  275.         count    = 1;
  276.     }
  277.  
  278.     if (count > 1 || (previous & 0xc0) == 0xc0)
  279.     {
  280.         count |= 0xc0;
  281.         Putbyte ( count , fp );
  282.     }
  283.     Putbyte(previous, fp);
  284. }
  285.  
  286. static unsigned long PixMap[8][16] =
  287. {
  288.     0x00000000L,    0x00000080L,    0x00008000L,    0x00008080L,
  289.     0x00800000L,    0x00800080L,    0x00808000L,    0x00808080L,
  290.     0x80000000L,    0x80000080L,    0x80008000L,    0x80008080L,
  291.     0x80800000L,    0x80800080L,    0x80808000L,    0x80808080L,
  292. };
  293.  
  294. static void
  295. ReadPlanes(y, width, buf, planes, bits)
  296. int        y;
  297. int        width;
  298. unsigned char    *buf;
  299. int        planes;
  300. int        bits;
  301. {
  302.     static int    first_time = 1;
  303.     unsigned char    *plane0, *plane1, *plane2, *plane3;
  304.     int        i, j, x;
  305.  
  306.     /*
  307.      * 256 color, 1 plane, 8 bits per pixel
  308.      */
  309.     if (planes == 1 && bits == 8)
  310.     {
  311.         for (x = 0; x < width; ++x)
  312.             buf[x] = ppm_lookupcolor( cht, &pixels[y][x] );
  313.         return;
  314.     }
  315.  
  316.     /*
  317.      * must be 16 colors or less, 4 planes or less, 1 bit per pixel
  318.      */
  319.     if (first_time)
  320.     {
  321.         for (i = 1; i < 8; ++i)
  322.             for (j = 0; j < 16; ++j)
  323.                 PixMap[i][j] = PixMap[0][j] >> i;
  324.         first_time = 0;
  325.     }
  326.  
  327.     i = (width + 7) / 8;
  328.  
  329.     plane0    = buf;
  330.     plane1    = plane0 + i;
  331.     plane2    = plane1 + i;
  332.     plane3    = plane2 + i;
  333.  
  334.     i    = 0;
  335.     x    = 0;
  336.  
  337.     while ( x < width )
  338.     {
  339.         register unsigned long    t;
  340.  
  341.         t     = PixMap[0][ppm_lookupcolor( cht, &pixels[y][x++] )];
  342.         t    |= PixMap[1][ppm_lookupcolor( cht, &pixels[y][x++] )];
  343.         t    |= PixMap[2][ppm_lookupcolor( cht, &pixels[y][x++] )];
  344.         t    |= PixMap[3][ppm_lookupcolor( cht, &pixels[y][x++] )];
  345.         t    |= PixMap[4][ppm_lookupcolor( cht, &pixels[y][x++] )];
  346.         t    |= PixMap[5][ppm_lookupcolor( cht, &pixels[y][x++] )];
  347.         t    |= PixMap[6][ppm_lookupcolor( cht, &pixels[y][x++] )];
  348.         t    |= PixMap[7][ppm_lookupcolor( cht, &pixels[y][x++] )];
  349.  
  350.         plane0[i] = t;
  351.         plane1[i] = t >> 8;
  352.         plane2[i] = t >> 16;
  353.         plane3[i++] = t >> 24;
  354.     }
  355. }
  356.  
  357. /*
  358.  * Write out a word to the PCX file
  359.  */
  360. static void
  361. Putword( w, fp )
  362. int w;
  363. FILE *fp;
  364. {
  365.         fputc( w & 0xff, fp );
  366.         fputc( (w / 256) & 0xff, fp );
  367. }
  368.  
  369. /*
  370.  * Write out a byte to the PCX file
  371.  */
  372. static void
  373. Putbyte( b, fp )
  374. int b;
  375. FILE *fp;
  376. {
  377.         fputc( b & 0xff, fp );
  378. }
  379.  
  380. /* The End */
  381.